home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Add-Ons / BBEdit / MacBob 1.0ß2 / Source / Bob / Scanner.cp < prev   
Encoding:
Text File  |  1995-12-11  |  7.0 KB  |  360 lines  |  [TEXT/KAHL]

  1. /***
  2.   *
  3.   *    Scanner.cp - lexical scanner
  4.   *
  5.   *    Original code: Copyright (c) 1991, by David Michael Betz.  All rights reserved
  6.   *    Modifications and additions: Copyright © by Christopher E. Hyde, 1995
  7.   *
  8.   ***/
  9.  
  10. #include "Bob.h"
  11. #include "Compiler.h"
  12.  
  13. // Some useful definitions
  14. #define    IfGetCh(tstCh, tok)    { if ((ch = GetCh()) == (tstCh)) return (tok);    \
  15.                         SaveCh(ch); }
  16. #define    Hex(c)            (isdigit(c) ? (c) - '0' : ((c) & 0x1F) + 9)
  17. #define    IsIdChar(ch)        (isalnum(ch) || ch == '_')            // Is this a valid identifier character
  18.  
  19. // Global variables
  20. SInt32    gTokVal;                    // numeric value
  21. char*    gTokStr;                    // token string
  22. TToken    pSaveTkn;                    // look ahead token
  23.  
  24. // Local variables
  25. static CIStream* inStream;            // input stream
  26. static int        pSaveCh;            // look ahead character
  27. static char*    pLine;                // last input line
  28. static char*    pLPtr;                // line pointer
  29. static int        pLineNum;            // line number
  30. static char    pKeywords[] = "class\0static\0if\0else\0while\0return"
  31.                               "\0for\0break\0continue\0do\0new\0nil\0";
  32.  
  33. // Prototypes
  34. static TToken    ReadToken        (void);
  35. static TToken    GetString        (void);
  36. static TToken    GetCharacter    (void);
  37. static int        LiteralChar        (void);
  38. static TToken    GetId            (int ch);
  39. static TToken    GetNumber        (int ch);
  40. static int        SkipSpaces        (void);
  41. static int        GetCh            (void);
  42.  
  43.  
  44. inline static void
  45. SaveCh (char ch)
  46. {
  47.     pSaveCh = ch;
  48. }
  49.  
  50.  
  51. // Initialize the scanner
  52. void
  53. InitScanner (CIStream& iStream)
  54. {
  55.     pLine = (char*) Calloc(kLineSize + kLitStrSize, 1);
  56.     gTokStr = &pLine[kLineSize];
  57.  
  58.         // Remember the getc function and data
  59.     inStream = &iStream;
  60.  
  61.         // Setup the line buffer
  62.     pLPtr = pLine;
  63.     *pLPtr = '\0';
  64.     pLineNum = 0;
  65.  
  66.         // No lookahead yet
  67.     SaveToken(kNoToken);
  68.     SaveCh(0);
  69. }
  70.  
  71.  
  72. // Get the next token
  73. TToken
  74. Token (void)
  75. {
  76.     TToken tkn = pSaveTkn;
  77.  
  78.     if (tkn != kNoToken)
  79.         SaveToken(kNoToken);
  80.     else
  81.         tkn = ReadToken();
  82.     return tkn;
  83. }
  84.  
  85.  
  86. // Get the name of a token
  87. KStr
  88. TokenName (TToken token)
  89. {
  90.     static Str15 aTokenStr;
  91.  
  92.     if (token == kEOF)
  93.         return "<eof>";
  94.     else if (token >= _kTokenMin && token <= _kTokenMax) {
  95.         GetIndString(aTokenStr, rTokenNames, token - _kTokenMin + 1);
  96.         aTokenStr[aTokenStr[0] + 1] = 0;
  97.         return KStr(&aTokenStr[1]);
  98.     }
  99.  
  100.     aTokenStr[0] = token;
  101.     aTokenStr[1] = '\0';
  102.     return KStr(aTokenStr);
  103. }
  104.  
  105.  
  106. // Read the next token
  107. static TToken
  108. ReadToken (void)
  109. {
  110.     int ch;
  111.  
  112.     // check the next character
  113.     for (;;)
  114.         switch (ch = SkipSpaces()) {
  115.         case EOF:        return kEOF;
  116.         case '"':        return GetString();
  117.         case '\'':        return GetCharacter();
  118.         case '<':        switch (ch = GetCh()) {
  119.                         case '=':
  120.                             return kLE;
  121.                         case '<':
  122.                             IfGetCh('=', kSHLEQ);
  123.                             return kSHL;
  124.                         default:
  125.                             SaveCh(ch);
  126.                             return '<';
  127.                         }
  128.         case '=':        IfGetCh('=', kEQ);
  129.                         return '=';
  130.         case '!':        IfGetCh('=', kNE);
  131.                         return '!';
  132.         case '>':        switch (ch = GetCh()) {
  133.                         case '=':
  134.                             return kGE;
  135.                         case '>':
  136.                             IfGetCh('=', kSHREQ);
  137.                             return kSHR;
  138.                         default:
  139.                             SaveCh(ch);
  140.                             return '>';
  141.                         }
  142.         case '%':        IfGetCh('=', kREMEQ);
  143.                         return '%';
  144.         case '&':        switch (ch = GetCh()) {
  145.                             case '&':                return kAND;
  146.                             case '=':                return kANDEQ;
  147.                             default:    SaveCh(ch);    return '&';
  148.                         }
  149.         case '|':        switch (ch = GetCh()) {
  150.                             case '|':                return kOR;
  151.                             case '=':                return kOREQ;
  152.                             default:    SaveCh(ch);    return '|';
  153.                         }
  154.         case '^':        IfGetCh('=', kXOREQ);
  155.                         return '^';
  156.         case '+':        switch (ch = GetCh()) {
  157.                             case '+':                return kINC;
  158.                             case '=':                return kADDEQ;
  159.                             default:    SaveCh(ch);    return '+';
  160.                         }
  161.         case '-':        switch (ch = GetCh()) {
  162.                             case '-':                return kDEC;
  163.                             case '=':                return kSUBEQ;
  164.                             case '>':                return kMemRef;
  165.                             default:    SaveCh(ch);    return '-';
  166.                         }
  167. #if qExtensions
  168.         case '.':        return kMemRef;
  169. #endif
  170.         case '*':        IfGetCh('=', kMULEQ);
  171.                         return '*';
  172.         case '/':        switch (ch = GetCh()) {
  173.                         case '=':
  174.                             return kDIVEQ;
  175.                         case '/':
  176.                             while ((ch = GetCh()) != EOF)
  177.                                 if (ch == '\r')
  178.                                     break;
  179.                             break;
  180.                         case '*':
  181.                             for (int ch2 = ch = EOF; (ch2 = GetCh()) != EOF; ch = ch2)
  182.                                 if (ch == '*' && ch2 == '/')
  183.                                     break;
  184.                             break;
  185.                         default:
  186.                             SaveCh(ch);
  187.                             return '/';
  188.                         }
  189.                         break;
  190.         case ':':        IfGetCh(':', kCC);
  191.                         return ':';
  192.         default:        if (isdigit(ch))
  193.                             return GetNumber(ch);
  194.                         else if (isalpha(ch))
  195.         case '_':            return GetId(ch);
  196.                         else
  197.                             return ch;
  198.         }
  199. }
  200.  
  201.  
  202. // Get a string
  203. static TToken
  204. GetString (void)
  205. {
  206.     int ch;
  207.  
  208.         // get the string
  209.     char* p = gTokStr;
  210.     while ((ch = LiteralChar()) != EOF && ch != '"') {
  211.         *p++ = ch;
  212.         if (p > &gTokStr[kLitStrLen])
  213.             ParseError("Literal string too long");
  214.     }
  215.     if (ch == EOF)
  216.         SaveCh(EOF);
  217.     gTokVal = p - gTokStr;
  218.  
  219.     return kString;
  220. }
  221.  
  222.  
  223. // Get a character constant
  224. static TToken
  225. GetCharacter (void)
  226. {
  227.     gTokVal = LiteralChar();
  228.  
  229.     if (GetCh() != '\'')
  230.         ParseError("Expecting a closing single quote");
  231.     return kNumber;
  232. }
  233.  
  234.  
  235. // Get a character from a literal string
  236. static int
  237. LiteralChar (void)
  238. {
  239.     int ch = GetCh();
  240.  
  241.     if (ch == '\\')
  242.         switch (ch = GetCh()) {
  243.             case '0':    ch = 0;                    break;
  244.             case 'n':    ch = 13;                break;    // Swap around \n and \r
  245.             case 'r':    ch = 10;                break;
  246.             case 't':    ch = '\t';                break;
  247. #if qExtensions
  248.             case 'x':
  249.                 ch = GetCh();
  250.                 int ch2 = GetCh();
  251.                 if (!isxdigit(ch) || !isxdigit(ch2))
  252.                     ParseError("Expecting 2 hex digits");
  253.                 ch = (Hex(ch) << 4) + Hex(ch2);
  254.                 break;
  255. #endif
  256.             case EOF:    ch = '\\'; SaveCh(EOF);    break;
  257.         }
  258.     return ch;
  259. }
  260.  
  261.  
  262. // Get an identifier
  263. static TToken
  264. GetId (int ch)
  265. {
  266.         // get the identifier
  267.     char* p = gTokStr; *p++ = ch;
  268.     while ((ch = GetCh()) != EOF && IsIdChar(ch)) {
  269.         *p++ = ch;
  270.         if (p > &gTokStr[kIdLen])
  271.             ParseError("Identifier name too long");
  272.     }
  273.     SaveCh(ch);
  274.     *p = '\0';
  275.  
  276.         // check to see if it is a keyword
  277.     int i = _kFirstKeyword;
  278.     for (KStr k = pKeywords; *k; ++i) {
  279.         if (strcmp(k, gTokStr) == 0)
  280.             return i;
  281.         while (*k++)
  282.             ;
  283.     }
  284.  
  285.     return kIdentifier;
  286. }
  287.  
  288.  
  289. // Get a number
  290. static TToken
  291. GetNumber (int ch)
  292. {
  293.     SInt32 num = ch - '0';
  294.  
  295.         // get the number
  296.     while ((ch = GetCh()) != EOF && isdigit(ch))
  297.         num = (num * 10) + ch - '0';
  298.  
  299.     gTokVal = num;
  300.     SaveCh(ch);
  301.  
  302.     return kNumber;
  303. }
  304.  
  305.  
  306. // Skip leading spaces
  307. static int
  308. SkipSpaces (void)
  309. {
  310.     int ch;
  311.  
  312.     while ((ch = GetCh()) != EOF && isspace(ch))
  313.         ;
  314.     return ch;
  315. }
  316.  
  317.  
  318. // Get the next character
  319. static int
  320. GetCh (void)
  321. {
  322.     int ch = pSaveCh;
  323.  
  324.     // check for a lookahead character
  325.     if (ch)
  326.         SaveCh(0);
  327.     else {        // check for a buffered character
  328.         while ((ch = (uchar) *pLPtr++) == '\0') {
  329.                 // check for being at the end of file
  330.             if (inStream->IsEOF())
  331.                 return EOF;
  332.  
  333.                 // read the next line
  334.             inStream->Get(pLPtr = pLine, kLineSize);
  335.             ++pLineNum;
  336.         }
  337.     }
  338.  
  339.     // return the current character
  340.     return ch;
  341. }
  342.  
  343.  
  344. // Report an error in the current line
  345. void
  346. ParseError (KStr msg)
  347. {
  348.         // Rredisplay the line with the error
  349.     PrintErrF(">>> %s <<<\r>>> in line %d <<<\r%s", msg, pLineNum, pLine);
  350.  
  351.     for (char* src = pLine; src < pLPtr - 1; ++src)
  352.         if (*src != '\t')
  353.             *src = ' ';
  354.     *src = '\0';
  355.     PrintErrF("%s^\r", pLine);
  356.  
  357.         // Invoke the error trap
  358.     Fail(errPrintedMessage);
  359. }
  360.